using System;
using System.Collections.Generic;
using System.Text;

namespace DatabaseCode.Data
{
  // Field は C++ コード上は構造体内のメンバ変数がある１行を指す。

  /* 読み込む文字列の例
   *  int item_code;     // 品名コード ●Item.code
   */
  class D4_Field
  {
    // Parse メソッドでインスタンス化するので 非公開
    private D4_Field()
    {
      this.m_typename = "";
      this.m_variablename = "";
      this.m_comment = "";
      this.m_isPrimarykey = false;
      this.m_hasReference = false;
      this.m_refTable = "";
      this.m_refMember = "";
    }

    //読み込むのは１行のみ。
    //  戻り値：field が null で、文字列の終端に達した場合は true。
    //  ref int pos:文字列の読み込み開始位置。読み込んだ分上書きする。
    //  out D4_Field field：インスタンス化に失敗した場合は null にする。
    public static bool Parse(string str, ref int pos, out D4_Field field)
    {
      D4_Field f = new D4_Field();
      int len = str.Length;
      string temp;
      bool is_slash;

      //変数型まで読み飛ばす
      //中括弧閉じ('{')にを見つけたらレコード読み込み終了
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (char.IsLetter(str[pos])) break;
        if (str[pos] == '}') goto Error;
      }
      if (pos >= len) goto EndStr;
      if (str[pos] == '\r') goto EndLine;

      //変数型を読み込む（例：int）
      temp = "";
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (!Utility.IsLetterOrDigit(str[pos]) && (str[pos] != ':')) break;
        temp += str[pos];
      }
      if (pos >= len) goto EndStr;
      if (str[pos] == '\r') goto EndLine;
      f.m_typename = temp;

      //変数名まで読み飛ばす
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (char.IsLetter(str[pos]) && str[pos] != '_') break;
      }
      if (pos >= len) goto EndStr;
      if (str[pos] == '\r') goto EndLine;

      //変数名を読み込む（例：no[kTextSize]）
      temp = "";
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (!Utility.IsLetterOrDigit(str[pos]) && str[pos] != '_' && 
            (str[pos] != '[') && (str[pos] != ']')) break;
        temp += str[pos];
        //ここで '(' が来たらデータ型読み込みは強制終了。（メンバ関数が来たため）
        if (str[pos] == '(') goto Error;
      }
      if (pos >= len) goto EndStr;
      if (str[pos] == '\r') goto EndLine;
      f.m_variablename = temp;

      //コメントまで読み飛ばす
      is_slash = false;
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (is_slash)
        {
          if (str[pos] == '/')
          {
            pos++; // 2文字目の '/' を飛ばす
            break;
          }
          else
          {
            Debug.AddMessageLine("警告：D4_Field.Parse 構文エラー :" + Utility.GetLine(str, pos));
            is_slash = false; // 多分ここに来たら構文エラー。"  int code; / / 品名コード" みたいな
          }
        }
        else
        {
          if (str[pos] == '/') is_slash = true;
        }
      }
      if (pos >= len) goto EndStr;
      if (str[pos] == '\r') goto EndLine;

      //コメントを読み込む
      temp = "";
      for (; pos < len && str[pos] != '\r'; pos++)
      {
        if (str[pos] == '\r')
        {
          break;
        }
        temp += str[pos];
        f.ReadMarkWithString(str.Substring(pos));
      }
      f.m_comment = temp;
      field = f;
      return false;

    EndLine: // 改行文字('\r')に達した
      pos++;
      if (pos >= len) goto EndStr;
    Error: // エラー
      field = null;
      return false;

    EndStr:  // 文字列の終端に達した
      field = null;
      return true;
    }

    //先頭が★なら主キー、●なら参照とする。
    //●ならその後参照文字列として読み込む
    //strの例：★ 品名分類コード ●ItemKind.code
    public void ReadMarkWithString(string str)
    {
      int i;

      if (str[0] == '★')
      {
        this.m_isPrimarykey = true;
      }
      if (str[0] == '●')
      {
        this.m_refTable = "";
        this.m_refMember = "";
        for (i = 1; i < str.Length; i++)
        {
          if (str[i] == '.')
          {
            i++;
            break;
          }
          if (Utility.IsLetterOrDigit(str[i]))
          {
            this.m_refTable += str[i];
          } else {
            break;
          }
        }
        for (; i < str.Length; i++)
        {
          if (Utility.IsLetterOrDigit(str[i]))
          {
            this.m_refMember += str[i];
          }
          else
          {
            break;
          }
        }
        this.m_hasReference = true;
      }
    }

    //参照しているテーブル（構造体）、メンバ名が一致するなら true を返す。
    public bool IsEqualReference(string tablename, string membername)
    {
      if (m_hasReference)
      {
        if (tablename == m_refTable && membername == m_refMember)
        {
          return true;
        }
      }
      return false;
    }

    public string Typename
    {
      get
      {
        return m_typename;
      }
    }
    public string Variablename
    {
      get
      {
        return m_variablename;
      }
    }
    public string Comment
    {
      get
      {
        return m_comment;
      }
    }
    public bool IsPrimarykey
    {
      get
      {
        return m_isPrimarykey;
      }
    }
    public bool HasReference
    {
      get
      {
        return m_hasReference;
      }
    }
    public string RefTable
    {
      get
      {
        return m_refTable;
      }
    }
    public string RefMember
    {
      get
      {
        return m_refMember;
      }
    }

    private string m_typename;     // 型名。intなど
    private string m_variablename; // 変数名。
    private string m_comment;      // コメント
    private bool m_isPrimarykey;   // 主キーなら true
    private bool m_hasReference;   // 参照データがあるなら true
    private string m_refTable;     // 参照データテーブル名
    private string m_refMember;    // 参照データメンバ名
  }
}
